package allod.camera

import java.awt.image.BufferedImage
import java.awt.{Color}
import java.awt.color.ColorSpace
import allod.som.{Lattice, LabeledLattice}
import Lattice.NeuronLocation

/**
 * Created by IntelliJ IDEA.
 * User: allod
 * Date: 8 квіт 2010
 * Time: 12:02:56
 */

class ImageConverter(val lattice: Lattice, val latticeColorSpace: ColorSpace) {
  private lazy val neuronsCache: Array[Array[Array[Int]]] = new Array(101, 256, 256)

  //initial caching
  //  val time = System.currentTimeMillis
  for (L <- 0 until 101; a <- 0 until 40; b <- 0 until 40) {
    val lab: List[Double] = List(L, a, b)
    val winner = lattice.closestNeuron(lab)
    neuronsCache(L)(a + 128)(b + 128) = cacheIndex(winner)
  }
  //  println("init caching time:" + (System.currentTimeMillis - time) + "ms")

  def convert(image: BufferedImage, labeledLattice: LabeledLattice[Color]): BufferedImage = {
    require(lattice == labeledLattice.peer)
    //
    //    val time = System.currentTimeMillis

    val width = image.getWidth(null)
    val height = image.getHeight(null)
    val result = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB)

    for (i <- 0 until width; j <- 0 until height) {
      val rgb = image.getRGB(i, j)
      val red: Int = (rgb >> 16) & 0xff;
      val green: Int = (rgb >> 8) & 0xff;
      val blue: Int = (rgb) & 0xff;
      val buffer = latticeColorSpace.fromRGB(Array(red.toFloat, green.toFloat, blue.toFloat))

      val L = buffer(0).toInt
      val a = buffer(1).toInt
      val b = buffer(2).toInt
      val cachedIndex = neuronsCache(L)(a + 128)(b + 128)
      val neuron = if (cachedIndex != 0) {
        uncacheIndex(cachedIndex)
      } else {
        val lab: List[Double] = List(L, a, b)
        val winner = lattice.closestNeuron(lab)
        neuronsCache(L)(a + 128)(b + 128) = cacheIndex(winner)
        winner
      }
      val color = labeledLattice.labelAt(neuron)
      result.setRGB(i, j, color.getRGB)
    }
    //
    //    println("cache" + (System.currentTimeMillis - time) + "ms")
    result
  }

  def cacheIndex(nIndex: NeuronLocation): Int = {
    return 1 + nIndex._1 * lattice.columns + nIndex._2
  }

  def uncacheIndex(cIndex: Int): NeuronLocation = {
    val column = (cIndex - 1) / lattice.columns
    val row = (cIndex - 1) % lattice.columns
    return (column, row)
  }
}